
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

#define TTY_FIRST (tty_table)
#define TTY_END (tty_table + NR_CONSOLES)

PRIVATE void init_tty(TTY* p_tty);
PRIVATE void tty_do_read(TTY* p_tty);
PRIVATE void tty_do_write(TTY* p_tty);
PRIVATE void put_key(TTY* p_tty, u32 key);

PUBLIC void task_tty() {
    total = 0;
    TTY* p_tty;
    init_keyboard();
    for(p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++) { // 初始化所有 TTY
        init_tty(p_tty);
    }
    //nr_current_console = 0; // 当前是哪个控制台
    select_console(0);
    while(1) {
        for(p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++) { // 对每个 TTY 进行读写操作
            tty_do_read(p_tty);
            tty_do_write(p_tty);
        }
    }
}

PRIVATE void tty_do_write(TTY* p_tty) {
    if(p_tty -> inbuf_count) { // 若缓冲区中有数据，则进行写入
        char ch = *(p_tty -> p_inbuf_tail);
        p_tty -> p_inbuf_tail++;
        if(p_tty -> p_inbuf_tail == p_tty -> in_buf + TTY_IN_BYTES)
            p_tty -> p_inbuf_tail = p_tty -> in_buf;
        p_tty -> inbuf_count--;
        out_char(p_tty -> p_console, ch);
    }
}

PRIVATE void tty_do_read(TTY* p_tty) {
    if(is_current_console(p_tty -> p_console)) // 判断当前TTY的控制台是不是当前控制台
        keyboard_read(p_tty); // 是，则读取缓冲区数据
}

PUBLIC void init_tty(TTY* p_tty) {
    // 初始化缓冲区
    p_tty -> inbuf_count = 0;
    p_tty -> p_inbuf_head = p_tty -> p_inbuf_tail = p_tty -> in_buf;

    // 初始化屏幕
    init_screen(p_tty);
}

PUBLIC void in_process(TTY* p_tty, u32 key) {
    char output[2] = {'\0', '\0'};
    if(!(key & FLAG_EXT)) {
        put_key(p_tty, key);
    } else {
        int raw_code = key & MASK_RAW;
        switch(raw_code) {
            case UP:
                if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R))
                    scroll_screen(p_tty -> p_console, SCR_DN);
                break;
            case DOWN:
                if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R))
                    scroll_screen(p_tty -> p_console, SCR_UP);
                break;
            case F1:
		    case F2:
		    case F3:
		    case F4:
		    case F5:
		    case F6:
		    case F7:
		    case F8:
		    case F9:
		    case F10:
		    case F11:
		    case F12:
		    	/* Alt + F1~F12 */
		    	if ((key & FLAG_ALT_L) || (key & FLAG_ALT_R)) {
		    		select_console(raw_code - F1);
		    	}
		    	break;
            case ENTER:
                put_key(p_tty, '\n');
                break;
            case BACKSPACE:
                put_key(p_tty, '\b');
                break;
            default:
                break;
        }
    }
}

PRIVATE void put_key(TTY* p_tty, u32 key) {
    // 当前 TTY 的缓冲区长度超过 TTY 允许的最大容量
    if(p_tty -> inbuf_count >= TTY_IN_BYTES) return;
    *(p_tty -> p_inbuf_head) = key;
    p_tty -> p_inbuf_head++;
    
    if(p_tty -> p_inbuf_head == p_tty -> in_buf + TTY_IN_BYTES)
        p_tty -> p_inbuf_head = p_tty -> in_buf;
    
    p_tty -> inbuf_count++;
}
